<template>
  <div class='bubble-chart'>
    <ul class="chartList">
      <li>
        <h4>使用html+css绘制柱状图</h4>
        <div class="bargraph">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
      </li>
      <li>
        <h4>使用html+css绘制饼图</h4>
        <div class="piegraph"></div>
      </li>
      <li>
        <h4>svg绘制柱状图</h4>
        <svg xmlns="http://www.w3.org/2000/svg" width="1.20rem" height="2rem" viewBox="0 0 60 100">
          <g transform="translate(0, 100) scale(1, -1)">
            <g>
              <rect x="1" y="0" width="10" height="25" fill="#37c"/>
              <rect x="13" y="0" width="10" height="26" fill="#37c"/>
              <rect x="25" y="0" width="10" height="40" fill="#37c"/>
              <rect x="37" y="0" width="10" height="45" fill="#37c"/>
              <rect x="49" y="0" width="10" height="68" fill="#37c"/>
            </g>
            <g>
              <rect x="1" y="0" width="10" height="15" fill="#3c7"/>
              <rect x="13" y="0" width="10" height="11" fill="#3c7"/>
              <rect x="25" y="0" width="10" height="17" fill="#3c7"/>
              <rect x="37" y="0" width="10" height="25" fill="#3c7"/>
              <rect x="49" y="0" width="10" height="37" fill="#3c7"/>
            </g>
          </g>
        </svg>
      </li>
      <li>
        <h4>canvas绘图</h4>
        <div>
          <canvas width="212" height="212" class="canvas"></canvas>
        </div>
      </li>
      <li>
        <h4>层次结构关系图</h4>
        <canvas width="380" height="300" class="drawCircle"></canvas>
      </li>
    </ul>
    <ul class="chartList2">
      <li>
        <h4>层次气泡结构关系图</h4>
        <canvas width="400" height="300" class="drawBox"></canvas>
      </li>
      <li>
        <h4>svg的使用</h4>
        <!-- svg里面的单位都是px像素，坐标系和canvas一致-->
        <h1 id="title"></h1>
        <svg xmlns="http://www.w3.org/2000/svg" class="svg" viewBox="0 0 400 300" version="1.1">
        </svg>
      </li>
    </ul>
  </div>
</template>

<script>
import * as d3 from 'd3-hierarchy'

export default {
  name: 'BubbleChart',
  props: {

  },
  components: {
  },
  data () {
    return {
      flag: false,
      root: {},
      name: undefined,
      hightX: null,
      hightY: null,
      dataSource: 'https://s5.ssl.qhres2.com/static/b0695e2dd30daa64.json'
    }
  },
  created () {

  },
  mounted () {
    this.canvasDraw()
    this.initRelation()
  },
  watch: {

  },
  methods: {
    // 使用canvas画图
    canvasDraw () {
      // 获取 Canvas 上下文
      const canvas = document.querySelector('canvas')
      const context = canvas.getContext('2d')
      // 利用 Canvas 上下文绘制图形
      const rectSize = [50, 50]
      context.fillStyle = 'red'
      context.beginPath()
      // 暂存画布当前状态
      context.save()
      // 平移画布中心点
      context.translate(-0.5 * rectSize[0], -0.5 * rectSize[1])
      context.rect(0.5 * canvas.width, 0.5 * canvas.height, ...rectSize)
      // 恢复画布状态
      context.restore()
      context.fill()
    },
    // 层次结构关系图
    async initRelation () {
      const baseData = await (await fetch(this.dataSource)).json()
      // 将数组内的一级叶子节点全部提取出来作为一个数组
      const regions = d3.hierarchy(baseData).sum(d => 1).sort((a, b) => { return b.value - a.value })
      const pack = d3.pack().size([400, 300]).padding(1)
      this.root = pack(regions)
      const drawBox = document.querySelector('.drawBox')
      const context = drawBox.getContext('2d')
      drawBox.addEventListener('mousemove', (e) => {
        this.hoverHight(this.root.children, e.offsetX, e.offsetY, context)
      })
      drawBox.addEventListener('mouseleave', () => {
        context.clearRect(0, 0, 400, 300)
        this.draw(context, this.root)
      })
      drawBox.addEventListener('click', (e) => {
        this.showTipBox(this.root.children, e.offsetX, e.offsetY, context)
      })
      this.draw(context, this.root)
      this.drawCircle(this.root)
      this.drawOfSvg()
    },
    // 画球
    drawBall (context, node, fillStyle1 = 'rgba(87, 164, 255, 1)', fillStyle2 = 'rgba(134, 187, 255, 1)') {
      const { x, y, r } = node
      const radgrad = context.createRadialGradient(x, y, r, x + 25, y - 30, r - r / 1.001)
      // 第一个圆周围
      radgrad.addColorStop(0, fillStyle1)
      // 第一个圆中心
      radgrad.addColorStop(0.01, fillStyle2)
      // 第二个圆中心
      radgrad.addColorStop(1, 'rgba(186, 216, 255, .99)')
      // 创建的径向渐变
      context.fillStyle = radgrad
      context.beginPath()
      context.arc(x, y, r, 0, Math.PI * 2)
      context.fill()
      context.fillStyle = 'rgba(94, 137, 255, 1)'
      context.font = '0.15rem Arial'
      context.textAlign = 'center'
      context.fillText(node.data.name, x + 2, y + 5)
    },
    // 画气泡图
    draw (context, node) {
      const children = node.children
      if (Array.isArray(children)) {
        children.forEach((item, index) => {
          this.drawBall(context, item)
        })
      }
    },
    // 画结构层次关系图
    drawCircle (node) {
      const drawBox = document.querySelector('.drawCircle')
      const context = drawBox.getContext('2d')
      const { x, y, r } = node
      const children = node.children
      context.fillStyle = 'rgba(134, 187, 255, .4)'
      context.beginPath()
      context.arc(x, y, r, 0, Math.PI * 2)
      context.fill()
      if (children) {
        children.forEach((item, index) => {
          this.drawCircle(item)
        })
      } else {
        context.fillStyle = 'rgba(0, 0, 0, 0.2)'
        context.font = '0.05rem Arial'
        context.textAlign = 'center'
        context.fillText(node.data.name, x, y)
      }
    },
    // 移入高亮显示
    hoverHight (children, x, y, context) {
      if (Array.isArray(children)) {
        children.forEach((item, index) => {
          if (x && y) {
            const hightX = Math.round(Math.pow((x - item.x), 2))
            const hightY = Math.round(Math.pow((y - item.y), 2))
            const hightR = Math.round(Math.pow(item.r, 2))
            if (hightX + hightY < hightR) {
              if (this.hightX && this.hightY) {
                if (this.hightX !== Math.round(item.x) && this.hightY !== Math.round(item.y)) {
                  this.flag = true
                }
              } else {
                this.hightX = Math.round(item.x)
                this.hightY = Math.round(item.y)
                this.flag = true
              }
              if (this.flag) {
                context.save()
                context.fillStyle = 'rgba(134, 187, 255, 0.4)'
                context.beginPath()
                context.arc(item.x, item.y, item.r, 0, Math.PI * 2)
                context.fill()
                context.restore()
                this.drawBall(context, item, 'rgba(94, 137, 255, 1)', 'rgba(94, 137, 255, 1)')
              }
              return false
            }
          }
        })
      }
    },
    // 点击的时候显示弹框
    showTipBox (children, x, y, context) {
      if (Array.isArray(children)) {
        children.forEach((item, index) => {
          if (x && y) {
            const hightX = Math.round(Math.pow((x - item.x), 2))
            const hightY = Math.round(Math.pow((y - item.y), 2))
            const hightR = Math.round(Math.pow(item.r, 2))
            if (hightX + hightY < hightR) {
              if (this.hightX && this.hightY) {
                if (this.hightX !== Math.round(item.x) && this.hightY !== Math.round(item.y)) {
                  this.flag = true
                }
              } else {
                this.hightX = Math.round(item.x)
                this.hightY = Math.round(item.y)
                this.flag = true
              }
              if (this.flag) {
                context.save()
                context.strokeStyle = 'rgba(87, 164, 255, 1)'
                context.fillStyle = 'rgba(134, 187, 255, .5)'
                context.beginPath()
                context.rect(item.x, item.y, item.r * 4, item.r * 2)
                context.fill()
                context.stroke()
                context.fillStyle = 'rgba(255, 255, 255, 1)'
                context.font = '0.15rem Arial'
                context.textAlign = 'left'
                item.name = ''
                item.data.children.forEach((d, index) => {
                  item.name += d.name + '、'
                })
                context.fillText(item.name, item.x + item.r, item.y + item.r)
                context.restore()
              }
              return false
            }
          }
        })
      }
    },
    // 使用svg绘制结构层次关系图
    drawOfSvg () {
      const svg = document.querySelector('.svg')
      const title = document.getElementById('title')
      let preDom = null
      svg.addEventListener('mousemove', (e) => {
        let target = e.target
        if (target.nodeName === 'text') {
          target = target.previousElementSibling
        }
        const childName = target.getAttribute('data-name')
        let parentName = null
        if (target.parentNode) {
          parentName = target.parentNode.previousElementSibling.getAttribute('data-name')
        }
        title.textContent = parentName ? parentName + '-' + childName : childName
        if (preDom !== target) {
          if (preDom) {
            preDom.setAttribute('fill', 'rgba(134, 187, 255, .4)')
          }
        }
        target.setAttribute('fill', 'rgba(0, 0, 0, 0.2)')
        preDom = target
      })
      this.createSvg(svg, this.root)
    },
    createSvg (dom, node, fillStyle = 'rgba(134, 187, 255, .4)', textColor = 'white') {
      const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
      const { x, y, r } = node
      circle.setAttribute('cx', x)
      circle.setAttribute('cy', y)
      circle.setAttribute('r', r)
      circle.setAttribute('data-name', node.data.name)
      circle.setAttribute('fill', fillStyle)
      dom.appendChild(circle)
      if (node.children) {
        const g = document.createElementNS('http://www.w3.org/2000/svg', 'g')
        node.children.forEach((item, index) => {
          this.createSvg(g, item)
        })
        dom.appendChild(g)
      } else {
        const text = document.createElementNS('http://www.w3.org/2000/svg', 'text')
        text.setAttribute('fill', textColor)
        text.setAttribute('font-family', 'Arial')
        text.setAttribute('font-size', '0.05rem')
        text.setAttribute('text-anchor', 'middle')
        text.setAttribute('x', x)
        text.setAttribute('y', y)
        text.textContent = node.data.name
        dom.appendChild(text)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.bubble-chart{
  height: 18rem;
  .chartList{
    display: grid;
    grid-template-columns: repeat(5, 18%);
  }
  .chartList2{
    display: grid;
    grid-template-columns: repeat(3, 30%);
    .svg{
      width: 100%;
      height: 100%;
    }
    li{
      position: relative;
      #title{
        left: 50%;
        top: 15%;
        transform: translateX(-50%);
        position: absolute;
      }
    }
  }
  .bargraph {
    display: grid;
    width: 1.50rem;
    height: 1rem;
    padding: .1rem;
    transform: scaleY(3);
    grid-template-columns: repeat(5, 20%);
  }
  .bargraph div {
    margin: 0 2px;
  }
  .bargraph div:nth-child(1) {
    background: linear-gradient(to bottom, transparent 75%, #37c 0, #37c 85%, #3c7 0);
  }
  .bargraph div:nth-child(2) {
    background: linear-gradient(to bottom, transparent 74%, #37c 0, #37c 89%, #3c7 0);
  }
  .bargraph div:nth-child(3) {
    background: linear-gradient(to bottom, transparent 60%, #37c 0, #37c 83%, #3c7 0);
  }
  .bargraph div:nth-child(4) {
    background: linear-gradient(to bottom, transparent 55%, #37c 0, #37c 75%, #3c7 0);
  }
  .bargraph div:nth-child(5) {
    background: linear-gradient(to bottom, transparent 32%, #37c 0, #37c 63%, #3c7 0);
  }
  .piegraph {
    display: inline-block;
    width: 1.50rem;
    height: 1.50rem;
    border-radius: 50%;
    // 圆锥渐变
    background-image: conic-gradient(#37c 30deg, #3c7 30deg, #3c7 65deg, orange 65deg, orange 110deg, #f73 110deg, #f73 200deg, #ccc 200deg);
  }
  .canvas{
    border: 1px solid black;
  }
  .drawBox{
    border: 1px solid black;
    background: rgba(134, 187, 255, .4);
  }
}
</style>
